package com.dbsop.operation.field;


import com.dbsop.common.enums.EsConstant;
import com.dbsop.domain.info.EsFiledInfo;
import com.dbsop.exception.EsRunException;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.admin.indices.get.GetIndexRequest;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.cluster.metadata.MappingMetaData;
import org.elasticsearch.common.collect.ImmutableOpenMap;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;

import java.io.IOException;
import java.util.*;

@Slf4j
public class TcFieldOperation implements FieldOperation {



    private TransportClient tc = null;

    public TcFieldOperation(TransportClient tc) {
        this.tc = tc;
    }

    public boolean checkField(Map<String,Object> properties,EsFiledInfo esFiledInfo){
        String type = (String) properties.get("type");
        Map<String,Object> subProperties = (Map<String, Object>) properties.get("properties");
        if (type == null && subProperties!=null &&  esFiledInfo.getChildFields()!=null){
            List<EsFiledInfo> childFields = esFiledInfo.getChildFields();

            for (EsFiledInfo childField : childFields) {
                String esFieldName = childField.getEsFieldName();
                Map<String,Object> childSub = (Map<String, Object>) subProperties.get("properties");
                if (childSub == null){
                    childSub = (Map<String, Object>) subProperties.get(childField.getEsFieldName());
                    if (childSub !=null && checkField(childSub,childField) ){
                        continue;
                    }else {
                        log.info("字段信息映射不符:"+childField.getFieldName());
                        return false;
                    }

                }
                Map<String,Object> esProSubProperties = (Map<String,Object>) childSub.get(esFieldName);
                if (esProSubProperties == null){
                    log.info("字段信息映射不符:"+childField.getFieldName());
                    return false;
                }
                if (!checkField(esProSubProperties,esFiledInfo)){
                    log.info("字段信息映射不符:"+childField.getFieldName());
                    return false;
                }
            }
            return true;
        }else if (esFiledInfo.getEsFieldType().equals(properties.get("type"))){
                return true;
        }
        log.info("字段信息映射不符:"+esFiledInfo.getFieldName());
        return false;
    }

    @Override
    public Boolean checkIndexFields(String indexName, Collection<EsFiledInfo> esFiledInfoList) {
        Map<String, Map<String,Object>> esFieldMap = getFields(indexName);
        for (EsFiledInfo esFiledInfo : esFiledInfoList) {
            Map<String, Object> properties = esFieldMap.get(esFiledInfo.getEsFieldName());
            if (properties == null){
                return false;
            }

            if (!checkField(properties,esFiledInfo)){
                return false;
            }
        }

        return false;
    }

    @Override
    public void checkContain(String indexName, Collection<EsFiledInfo> esFiledInfoList) {
        Map<String, Map<String,Object>> esFieldMap = getFields(indexName);
        for (EsFiledInfo esFiledInfo : esFiledInfoList) {
            Map<String, Object> properties = esFieldMap.get(esFiledInfo.getEsFieldName());
            if (properties == null)throw new EsRunException("ES field:" + esFiledInfo.getEsFieldName() + " Not Found !!!");
            boolean checkField = checkField(properties, esFiledInfo);
            if (!checkField){
                throw new EsRunException("ES field:" + esFiledInfo.getEsFieldName() + " FIELD INCONFORMITY !!!!");
            }
        }
    }

    @Override
    public Map<String, Map<String, Object>> getFields(String indexName) {
        Map<String,Map<String, Object>> fieldMap = new LinkedHashMap<String, Map<String, Object>>();
        ImmutableOpenMap<String, MappingMetaData> immutableOpenMap =
                tc.admin().indices().getIndex(new GetIndexRequest().indices(indexName))
                .actionGet().getMappings().get(indexName);
        try{
            Map<String, Map<String, Object>>  properties =
                    (Map<String,Map<String, Object>>) immutableOpenMap.get(EsConstant._TYPE).getSourceAsMap().get("properties");
            if (properties != null){
                fieldMap.putAll(properties);
            }
        }catch (NullPointerException e){
        }
        return fieldMap;
    }


    private void loadingXContentBuilder(XContentBuilder xContentBuilder, Collection<EsFiledInfo> esFiledInfoList,String ... parentFields){
        try {
            for (EsFiledInfo esFiledInfo : esFiledInfoList) {
                String esFieldType = esFiledInfo.getEsFieldType();
                String esFieldName = esFiledInfo.getEsFieldName();
                xContentBuilder.startObject(esFieldName);
                xContentBuilder.field("type", esFieldType);
                if (esFiledInfo.getAnalyzer()!=null){
                    xContentBuilder.field("analyzer",esFiledInfo.getAnalyzer());
                }
                List<EsFiledInfo> childFields = esFiledInfo.getChildFields();
                if (childFields!=null){
                    xContentBuilder.startObject("properties");
                    loadingXContentBuilder(xContentBuilder, childFields);
                    xContentBuilder.endObject();
                }
                xContentBuilder.endObject();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    @Override
    public void createIndexFiled(String indexName, Collection<EsFiledInfo> esFiledInfoList) {
        try {
            XContentBuilder xContentBuilder = XContentFactory.jsonBuilder().startObject().startObject("properties");
            loadingXContentBuilder(xContentBuilder, esFiledInfoList);
            xContentBuilder.endObject().endObject();
            boolean acknowledged = tc.admin().indices().preparePutMapping(indexName).setType(EsConstant._TYPE).setSource(xContentBuilder)
                    .execute().actionGet().isAcknowledged();
            if (acknowledged) log.info("索引添加字段成功: " + indexName);
            else log.info("索引添加字段失败: " + indexName);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }



}
